// Copyright (c) [2019] [huazhonghua]
// [理解] is licensed under the Mulan PSL v1.
// You can use this software according to the terms and conditions of the Mulan PSL v1.
// You may obtain a copy of Mulan PSL v1 at:
//     http://license.coscl.org.cn/MulanPSL
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v1 for more details.

#ifndef DEBUG_H
#define DEBUG_H

#include <stdio.h>

#include "structure.h"
#include "basic.h"
#include "labels.h"

void print_char_list(List* list) {
	wchar_t chars[list->length + 1];
	for(int i = 0; i < list->length; ++i) {
		chars[i] = list->nodes[i]->part;
	}
	chars[list->length] = L'\0';

	printf("%ls", chars);
}

void fprint_char_list(FILE* file, List* list) {
	wchar_t chars[list->length + 1];
	for(int i = 0; i < list->length; ++i) {
		chars[i] = list->nodes[i]->part;
	}
	chars[list->length] = L'\0';

	fprintf(file, "%ls", chars);
}

void print_string(Node* string) {
	print_char_list(string->other.pointer);
}

void fprint_string(FILE* file, Node* string) {
	fprint_char_list(file, string->other.pointer);
}

int print_node_string(Node* node) {
	if(node == NULL) 0;
	Node* string = get_linked(node, STRING);
	if(string != NULL) {
		print_char_list(string->other.pointer);
		return 1;
	}
	return 0;
}

int fprint_node_string(FILE* file, Node* node) {
	if(node == NULL) 0;
	Node* string = get_linked(node, STRING);
	if(string != NULL) {
		fprint_char_list(file, string->other.pointer);
		return 1;
	}
	return 0;
}

void print_node(Node* node) {
	if(node == NULL) {
		printf("NULL");
		return;
	}

	if(is_instance_of(node, STRING)) {
		print_string(node);
	}
	else if(is_instance_of(node, LIST)) {
		int length = get_list_node_length(node);
		for(int i = 0; i < length; ++i) {
			if(i > 0) {
				printf(" ");
			}

			Node* item = get_list_node_item(node, i);
			print_node(item);
		}
	}
	else if(!print_node_string(node)) {
		Node* type = get_linked(node, TYPE);
		if(is_tier_1(type, INTEGER)) {
			printf("int ");
		}
		printf("%d", node->part);
	}
}

void fprint_node(FILE* file, Node* node) {
	if(node == NULL) {
		fprintf(file, "NULL");
		return;
	}

	if(is_instance_of(node, STRING)) {
		fprint_string(file, node);
	}
	else if(is_instance_of(node, LIST)) {
		int length = get_list_node_length(node);
		for(int i = 0; i < length; ++i) {
			if(i > 0) {
				fprintf(file, " ");
			}
			Node* item = get_list_node_item(node, i);
			fprint_node(file, item);
		}
	}
	else if(!fprint_node_string(file, node)) {
		Node* type = get_linked(node, TYPE);
		if(is_tier_1(type, INTEGER)) {
			fprintf(file, "int ");
		}
		fprintf(file, "%d", node->part);
	}
}

void fprint_child(FILE* file, Node* node) {
	if(node == NULL) {
		fprintf(file, "NULL");
		return;
	}

	int length = node->table->buckets_size;
	for(int i = 0; i < length; ++i) {
		Bucket* bucket = node->table->buckets[i];
		if(bucket != NULL) {
			for(int j = 0; j < bucket->length; ++j) {
				Link* link = bucket->links[j];
				fprintf(file, "link %d ", link->part);
				fprint_node(file, link->target);
				fprintf(file, " ");
			}
		}
	}
	fflush(file);
}


void print_type(Node* node) {
	Node* type = get_linked(node, TYPE);
	print_node(type);
}

void print_int_list(List* list) {
	printf("l: %d\n", list->length);
	for(int i = 0; i < list->length; ++i) {
		if(i > 0) {
			printf(".");
		}
		printf("%d", list->nodes[i]->other.c_int);
	}
}

void print_list(List* list) {
	printf("{");
	for(int i = 0; i < list->length; ++i) {
		if(i > 0) printf(", ");
		print_node(list->nodes[i]);
	}
	printf("}");
}

#endif
